// Copyright 2024 awol2005ex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Kinit library - Kerberos authentication using password or keytab
//!
//! This library provides functionality for Kerberos authentication similar to the kinit command.
//! It supports both password and keytab authentication modes.

pub mod auth;
pub mod config;
pub mod keytab;
pub mod utils;

pub use auth::{kinit_with_password, kinit_with_keytab};
pub use config::{get_kdc_ip_from_config, parse_krb5_conf_for_kdc, get_default_keytab_path, get_keytab_from_config, parse_krb5_conf_for_keytab};
pub use keytab::load_key_from_keytab;
pub use utils::parse_principal;

use awol2005ex_kerbeiros::Credential;
use std::error::Error;

/// Main kinit function that handles both password and keytab authentication
pub fn kinit(
    principal: &str,
    auth_method: AuthMethod,
    kdc_server: &str,
) -> Result<Credential, Box<dyn Error>> {
    match auth_method {
        AuthMethod::Password(password) => kinit_with_password(principal, &password, kdc_server),
        AuthMethod::Keytab(keytab_path) => kinit_with_keytab(&keytab_path, principal, kdc_server),
    }
}

/// Authentication method enum
#[derive(Debug, Clone)]
pub enum AuthMethod {
    Password(String),
    Keytab(String),
}

/// Kinit configuration
#[derive(Debug, Clone)]
pub struct KinitConfig {
    pub principal: String,
    pub auth_method: AuthMethod,
    pub kdc_server: Option<String>,
    pub verbose: bool,
    pub lifetime: Option<String>,
    pub renewable_life: Option<String>,
    pub forwardable: bool,
    pub proxiable: bool,
    pub no_addresses: bool,
}

impl KinitConfig {
    pub fn new(principal: &str, auth_method: AuthMethod) -> Self {
        Self {
            principal: principal.to_string(),
            auth_method,
            kdc_server: None,
            verbose: false,
            lifetime: None,
            renewable_life: None,
            forwardable: false,
            proxiable: false,
            no_addresses: false,
        }
    }

    pub fn with_kdc_server(mut self, kdc_server: &str) -> Self {
        self.kdc_server = Some(kdc_server.to_string());
        self
    }

    pub fn with_verbose(mut self, verbose: bool) -> Self {
        self.verbose = verbose;
        self
    }

    pub fn with_lifetime(mut self, lifetime: &str) -> Self {
        self.lifetime = Some(lifetime.to_string());
        self
    }

    pub fn with_renewable_life(mut self, renewable_life: &str) -> Self {
        self.renewable_life = Some(renewable_life.to_string());
        self
    }

    pub fn with_forwardable(mut self, forwardable: bool) -> Self {
        self.forwardable = forwardable;
        self
    }

    pub fn with_proxiable(mut self, proxiable: bool) -> Self {
        self.proxiable = proxiable;
        self
    }

    pub fn with_no_addresses(mut self, no_addresses: bool) -> Self {
        self.no_addresses = no_addresses;
        self
    }
}